﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace MathService
{

    public class MNK
    {
        private double[] f_A;
        private int f_M;
        private double[] f_XData;
        private double[] f_YData;

        public MNK(double[] X, double[] Y, int m)
        {
            f_XData = X;
            f_YData = Y;
            f_M = m;
            Initialize();
        }

        public double Approximate(double x)
        {
            return F(f_A, x);
        }

        private static double F(IList<double> A, double x)
        {
            Contract.Requires(A.Count > 0);
            var lv_x = x;
            var lv_Result = A[0];
            for(var i = 1; i < A.Count; i++)
            {
                lv_Result += A[i] * lv_x;
                lv_x *= x;
            }
            return lv_Result;
        }

        public Func<double, double> GetApproximation()
        {
            var lv_A = f_A;
            return x => F(lv_A, x);
        }

        private void Initialize()
        {
            var matrix = new Matrix(f_XData.Length, f_M, (i, j) => Math.Pow(f_XData[i], j));
            var transponse = matrix.GetTransponse();
            var matrix3 = (((transponse * matrix)).GetImverse() * transponse) * f_YData;
            f_A = new double[matrix3.N];
            for(var i = 0; i < f_A.Length; i++)
                f_A[i] = matrix3[i, 0];
        }

        public static implicit operator Func<double, double>(MNK mnk)
        {
            return mnk.GetApproximation();
        }
    }
}

